The ooc Language
Today I've decided to have a quick look at ooc and see if I can accomplish the eBeats challenge in a day.
First of all, it seems like a nice little language, a pretty frontend for C, with some of the ideals of Nimrod, but with a lot more pragmatism.
I've joined #ooc-lang on freenode to get some help along the way.
To start calculating eBeats, we need the current time in UTC, so let's look at what the documentation says: os/Time. Looking at this, I suddenly realize that I have little to no idea of what the docs say, so I better read through the less terse material first. I notice however that there doesn't seem to be anything related to UTC or GMT on this page, that doesn't look good.
Working on getting anything recognizable from gmtime_r(3) doesn't turn out to be easy, but after 2 hours I've finally done it and see some actual times:
include time
import os/Time
import lang/Format
// struct tm *gmtime_r(const time_t *timep, struct tm *result);
gmtime_r: extern func(TimeT*, TMStruct*) -> TMStruct*
main: func () {
clock : TimeT
time(clock&)
time : TMStruct
gmtime_r(clock&, time&)
"%02i:%02i:%02i" cformat(time tm_hour, time tm_min, time tm_sec) println()
}
OK, so far everything seems fine, it's nothing to be proud of, but I won't stop here.
After some more fiddling, I come up with a timeToBeats
function that takes
the time struct and spits out the integer value of eBeats, but I seemingly
cannot get anything more fine-grained. Let's see if you can find the bug.
timeToBeats: func (time: TMStruct) -> Float {
beats := ((time tm_hour) * (1000.0 / 24.0)) +
((time tm_min) * (1000.0 / (24.0 * 60.0))) +
((time tm_sec) * (1000.0 / (24.0 * 60.0 * 60.0)))
return beats
}
Done looking?
Well, anytime a developer uses Floats, everything has to be checked more than
twice.
In my case, after a little bit of further investigation and sprinkling
cformat
/println
all over the place, I found that beats
wasn't a Float
,
it was an Int
, and ooc was so kind to just let me return an Int
from a
function that has Float
as explicit return type. What it did, and what I
cannot understand in modern language design, is that it implicitly converted
the Int
into a Float
, no warnings given, no questions asked.
Let's have a closer look at what's going on there, with a little experiment.
To keep it simple, I just divide a Float
by an Int
.
10.0 / 5 // 2.000000
The compiler says, when asked for really verbose output:
Resolving variable decl uniqueVar : <unknown type> = 10.0 / 5
For uniqueVar : Float = 10.0 / 5, resolving type Float, of type BaseType
So we really got a Float
as result, wonderful!
And now we divide an Int
by a Float
10 / 5.0 // 0.000000
The compiler says, when asked for really verbose output:
Resolving variable decl uniqueVar : <unknown type> = 10 / 5.0
For uniqueVar : SSizeT = 10 / 5.0, resolving type SSizeT, of type BaseType
Well, whatever SSizeT
is, it doesn't talk or walk like a Float
, and the
result is way worse than I had expected.
I'm running out of time to finish the post today, so I'll continue with the eBeats instead of diving further into the typing peculiarities of OCC.
After telling it that my return value really, really, is a Float
, it complied and gave me the desired result. Here is the finished source:
include time
import os/Time
// struct tm *gmtime_r(const time_t *timep, struct tm *result);
gmtime_r: extern func(TimeT*, TMStruct*) -> TMStruct*
main: func () {
clock : TimeT
time(clock&)
time : TMStruct
gmtime_r(clock&, time&)
"@%f" cformat(timeToBeats(time)) println()
}
timeToBeats: func (time: TMStruct) -> Float {
beats : Float
beats = ((time tm_hour) * (1000.0 / 24.0)) +
((time tm_min) * (1000.0 / (24.0 * 60.0))) +
((time tm_sec) * (1000.0 / (24.0 * 60.0 * 60.0)))
return beats
}
Future updates will go directly into the git repo. I of course welcome any contributions.